package com.have.blog.admin.service.impl;

import com.github.pagehelper.PageHelper;
import com.have.blog.admin.constant.AdminBlogConstant;
import com.have.blog.admin.constant.AdminMessageConstant;
import com.have.blog.admin.dao.BlogCategoryRelationDao;
import com.have.blog.admin.dao.BlogDao;
import com.have.blog.admin.dao.BlogTagRelationDao;
import com.have.blog.admin.domain.bo.AdminUserDetail;
import com.have.blog.admin.domain.dto.*;
import com.have.blog.admin.redis.AdminBlogCacheService;
import com.have.blog.admin.service.AdminBlogService;
import com.have.blog.admin.service.AdminService;
import com.have.blog.admin.service.SystemParamService;
import com.have.blog.admin.utils.SecurityUtil;
import com.have.blog.base.enums.BlogOriginal;
import com.have.blog.base.enums.BlogPublishStatus;
import com.have.blog.base.enums.BlogStatus;
import com.have.blog.base.wrapper.Wrapper;
import com.have.blog.config.configs.jwt.Audience;
import com.have.blog.model.mapper.*;
import com.have.blog.model.models.*;
import com.have.blog.picture.service.PictureFeignApi;
import com.have.blog.utils.DateUtils;
import com.have.blog.utils.MyBeanUtils;
import com.have.blog.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Service
@Slf4j
@SuppressWarnings("all")
public class AdminBlogServiceImpl implements AdminBlogService {
    @Autowired
    private BlogMapper blogMapper;
    @Autowired
    private BlogDao blogDao;
    @Autowired
    private BlogTagRelationDao blogTagRelationDao;
    @Autowired
    private BlogCategoryRelationDao blogCategoryRelationDao;
    @Autowired
    private TagMapper tagMapper;
    @Autowired
    private BlogCategoryMapper blogCategoryMapper;
    @Autowired
    private SystemParamService systemParamService;
    @Autowired
    private Audience audience;
    @Autowired
    private AdminBlogCacheService blogCacheService;
    @Autowired
    private PictureFeignApi pictureFeignApi;
    @Autowired
    private AdminService adminService;
    @Autowired
    private BlogTagRelationMapper relationMapper;

    @Override
    public List<BlogDto> getList(BlogDto blogDto) {
        PageHelper.startPage(blogDto.getPageNum(), blogDto.getPageSize());

        BlogExample example = new BlogExample();
        BlogExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotEmpty(blogDto.getKeyword()) && StringUtils.isNotEmpty(blogDto.getKeyword().trim())) {
            criteria.andTitleLike("%" + blogDto.getKeyword() + "%");
        }
        if (blogDto.getLevel() != null) {
            criteria.andLevelEqualTo(blogDto.getLevel());
        }
        if (blogDto.getIsPublish() != null) {
            criteria.andIsPublishEqualTo(blogDto.getIsPublish());
        }
        if (blogDto.getIsOriginal() != null) {
            criteria.andIsOriginalEqualTo(blogDto.getIsOriginal());
        }
        if(blogDto.getType() != null) {
            criteria.andTypeEqualTo(blogDto.getType());
        }
        if (!CollectionUtils.isEmpty(blogDto.getTagUid())) {
            BlogTagRelationExample tagRelationExample = new BlogTagRelationExample();
            tagRelationExample.createCriteria().andTagUidIn(blogDto.getTagUid());
            List<BlogTagRelation> blogTagRelations = relationMapper.selectByExample(tagRelationExample);
            if (CollectionUtils.isEmpty(blogTagRelations)) {
                return new ArrayList<>();
            }
            List<Integer> uids = new ArrayList<>();
            for (BlogTagRelation item : blogTagRelations) {
                uids.add(item.getBlogUid());
            }
            criteria.andUidIn(uids);
        }
        criteria.andStatusEqualTo(BlogStatus.ENABLE.getStatus());

        if (StringUtils.isNotEmpty(blogDto.getOrderByAscColumn())) {
            String column = StringUtils.underLine(new StringBuffer(blogDto.getOrderByAscColumn())).toString();
            example.setOrderByClause(column + " asc");
        } else if(StringUtils.isNotEmpty(blogDto.getOrderByDescColumn())) {
            // 将驼峰转换成下划线
            String column = StringUtils.underLine(new StringBuffer(blogDto.getOrderByDescColumn())).toString();
            example.setOrderByClause(column + " desc");
        } else {
            if (blogDto.getUseSort() == null || blogDto.getUseSort() == 0) {
                example.setOrderByClause("create_time desc");
            } else {
                example.setOrderByClause("sort_count desc");
            }
        }

        List<Blog> blogList = blogMapper.selectByExample(example);

        List<BlogDto> resultList = MyBeanUtils.copyListProperties(blogList, BlogDto::new);
        if (CollectionUtils.isEmpty(blogList)) {
            return resultList;
        }

        List<Integer> coverUids = new ArrayList<>();
        List<Integer> categoryUids = new ArrayList<>();
        List<Integer> blogUids = new ArrayList<>();
        resultList.forEach(item -> {
            if (item.getCoverUid() != null) {
                coverUids.add(item.getCoverUid());
            }
            if (item.getBlogCategoryUid() != null) {
                categoryUids.add(item.getBlogCategoryUid());
            }
            blogUids.add(item.getUid());
        });

        Map<Integer, String> picMap = new HashMap<>();
        Map<Integer, BlogCategoryDto> blogCategoryMap = new HashMap<>();
        if (categoryUids.size() > 0) {
            BlogCategoryExample blogCategoryExample = new BlogCategoryExample();
            blogCategoryExample.createCriteria()
                    .andUidIn(categoryUids);
            List<BlogCategory> categoryList = blogCategoryMapper.selectByExample(blogCategoryExample);
            if(!CollectionUtils.isEmpty(categoryList)) {
                List<BlogCategoryDto> blogCategoryDtos = MyBeanUtils.copyListProperties(categoryList, BlogCategoryDto::new);
                blogCategoryDtos.forEach(item -> {
                    blogCategoryMap.put(item.getUid(), item);
                });
            }
        }
        if (!CollectionUtils.isEmpty(coverUids)) {
            Wrapper<Map<Integer, String>> pictureWrapper = pictureFeignApi.getPicturesUrl(coverUids);
            if (pictureWrapper.isSuccess()) {
                picMap = pictureWrapper.getData();
            } else {
                log.error("获取图片失败, 方法：【AdminBlogGetList】");
            }
        }
        for (BlogDto blog : resultList) {
            List<Integer> tagUids = blogTagRelationDao.getTagUidsByBlogUid(blog.getUid());
            if (!CollectionUtils.isEmpty(tagUids)) {
                TagExample tagExample = new TagExample();
                tagExample.createCriteria().andUidIn(tagUids);
                List<Tag> tags = tagMapper.selectByExample(tagExample);
                List<BlogTagDto> blogTagDtos = MyBeanUtils.copyListProperties(tags, BlogTagDto::new);
                blog.setTagList(blogTagDtos);
                blog.setPhotoUrl(picMap.get(blog.getCoverUid()));
                blog.setBlogCategory(blogCategoryMap.get(blog.getBlogCategoryUid()));
            }
            blog.setBlogCategory(blogCategoryMap.get(blog.getBlogCategoryUid()));
        }
        return resultList;
    }

    @Override
    public Long getBlogCount(Integer status) {
        BlogExample example = new BlogExample();
        BlogExample.Criteria criteria = example.createCriteria();
        criteria.andStatusEqualTo(status)
                .andIsPublishEqualTo(BlogPublishStatus.PUBLISH.getStatus());
        Long count = blogMapper.countByExample(example);
        return count;
    }

    @Override
    public List<BlogTagDto> getBlogCountByTag() {
        // 获取标签和归属于此标签的文章总数
        List<Map<String, Object>> blogCountByTag = blogTagRelationDao.getBlogCountAccordingToTag();
        HashMap<Integer, Object> tagMap = new HashMap<>();
        for (Map<String, Object> item : blogCountByTag) {
            tagMap.put((int) item.get("tag_uid"), item.get("count"));
        }
        TagExample example = new TagExample();
        example.createCriteria()
                .andStatusEqualTo(BlogStatus.ENABLE.getStatus());
        List<Tag> tagList = tagMapper.selectByExample(example);
        List<BlogTagDto> blogTagDtos = MyBeanUtils.copyListProperties(tagList, BlogTagDto::new);
        for (BlogTagDto blogTagDto : blogTagDtos) {
            blogTagDto.setCount((long) tagMap.getOrDefault(blogTagDto.getUid(), 0l));
        }
        return blogTagDtos;
    }

    @Override
    public List<BlogCategoryDto> getBlogCountByCategory() {
        List<Map<String, Object>> blogCountAccordingToCategory = blogCategoryRelationDao.getBlogCountAccordingToCategory();
        HashMap<Integer, Object> categoryCountMap = new HashMap<>();
        for (Map<String, Object> item : blogCountAccordingToCategory) {
            Integer categoryUid = (int) item.get("blog_category_uid");
            categoryCountMap.put(categoryUid,  item.get("count"));
        }
        BlogCategoryExample example = new BlogCategoryExample();
        example.createCriteria().andStatusEqualTo(BlogStatus.ENABLE.getStatus());
        List<BlogCategory> categoryList = blogCategoryMapper.selectByExample(example);
        List<BlogCategoryDto> blogCategoryDtos = MyBeanUtils.copyListProperties(categoryList, BlogCategoryDto::new);
        for (BlogCategoryDto blogCategoryDto : blogCategoryDtos) {
            blogCategoryDto.setCount((long) categoryCountMap.getOrDefault(blogCategoryDto.getUid(), 0l));
        }
        return blogCategoryDtos;
    }

    @Override
    public ContributionCountVo getBlogContributeCount() {
        // 获取今天结束时间
        String endTime = DateUtils.getNowTime();
        // 获取365天前的日期
        Date temp = DateUtils.getDate(endTime, -365);
        String startTime = DateUtils.dateTimeToStr(temp);
        List<String> contributeDate = new ArrayList<>();
        contributeDate.add(startTime);
        contributeDate.add(endTime);

        List<Map<String, Object>> countAccordingToMonth = blogDao.getCountAccordingToMonth(startTime, endTime);
        List<String> dateList = DateUtils.getDayBetweenDates(startTime, endTime);
        Map<String, Object> dateMap = new HashMap<>();
        for (Map<String, Object> itemMap : countAccordingToMonth) {
            dateMap.put(itemMap.get("DATE").toString(), itemMap.getOrDefault("COUNT", 0l));
        }

        List<List<Object>> monthCountList = new ArrayList<>();
        for (String item : dateList) {
            Long count = 0l;
            if (dateMap.get(item) != null) {
                count = Long.valueOf(dateMap.get(item).toString());
            }
            List<Object> tempList = new ArrayList<>();
            tempList.add(item);
            tempList.add(count);
            monthCountList.add(tempList);
        }

        ContributionCountVo contributionCountVo = new ContributionCountVo();
        contributionCountVo.setStartTime(startTime);
        contributionCountVo.setEndTime(endTime);
        contributionCountVo.setBlogContributeCount(monthCountList);
        contributionCountVo.setBlogContributeDate(contributeDate);
        return contributionCountVo;
    }


    @Transactional
    @Override
    public Wrapper add(BlogDto blogDto) {
        BlogExample example = new BlogExample();
        BlogExample.Criteria criteria = example.createCriteria();
        criteria.andLevelEqualTo(blogDto.getLevel())
                .andStatusEqualTo(BlogStatus.ENABLE.getStatus());
        long count = blogMapper.countByExample(example);
        Wrapper wrapper = addVerdict(count + 1, blogDto.getLevel());
        if (wrapper != null) {
            return wrapper;
        }
        Blog blog = new Blog();
        MyBeanUtils.copyProperties(blogDto, blog);
        blog.setStatus(BlogStatus.ENABLE.getStatus());
        blog.setSortCount(0);
        String projectName = systemParamService.getSystemParamValueByKey(AdminBlogConstant.PROJECT_NAME_);
        if (BlogOriginal.ORIGINAL.equals(blogDto.getIsOriginal())) {
            Admin admin = adminService.getCurrentAdmin();
            if (admin != null) {
                if (StringUtils.isNotEmpty(admin.getNickname())) {
                    blog.setAuthor(admin.getNickname());
                } else {
                    blog.setAuthor(admin.getUsername());
                }
                blog.setAdminUid(admin.getUid());
            }
            blog.setArticlesCitations(projectName);
        } else {
            blog.setAuthor(blogDto.getAuthor());
            blog.setArticlesCitations(blogDto.getArticlesPart());
        }
        blog.setArticleSource(0);
        int insert = blogMapper.insert(blog);
        List<Integer> tagUid = blogDto.getTagUid();
        for (Integer integer : tagUid) {
            BlogTagRelation relation = new BlogTagRelation();
            relation.setBlogUid(blog.getUid());
            relation.setTagUid(integer);
            relationMapper.insert(relation);
        }

        if (insert > 0) {
            return Wrapper.success();
        }
        return Wrapper.failed();
    }

    @Transactional
    @Override
    public Wrapper edit(BlogDto blogDto) {
        BlogExample example = new BlogExample();
        example.createCriteria()
                .andUidEqualTo(blogDto.getUid());
        List<Blog> blogs = blogMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(blogs)) return Wrapper.failed();
        Blog blog = blogs.get(0);
        example.clear();
        example.createCriteria()
                .andLevelEqualTo(blogDto.getLevel())
                .andStatusEqualTo(BlogStatus.ENABLE.getStatus());
        long count = blogMapper.countByExample(example);
        if (blog != null) {
            if (blog.getLevel().equals(blogDto.getLevel())) {
                count += 1;
            }
        }
        Wrapper wrapper = addVerdict(count, blogDto.getLevel());
        if (wrapper != null) {
            return wrapper;
        }
        MyBeanUtils.copyProperties(blogDto, blog);
        AdminUserDetail userDetail = SecurityUtil.getUserDetail();
        Admin admin = userDetail.getAdmin();
        blog.setAdminUid(admin.getUid());
        if (BlogOriginal.ORIGINAL.equals(blogDto.getIsOriginal())) {
            if (StringUtils.isNotEmpty(admin.getNickname())) {
                blog.setAuthor(admin.getNickname());
            } else {
                blog.setAuthor(admin.getUsername());
            }
            String projectName = systemParamService.getSystemParamValueByKey(AdminBlogConstant.PROJECT_NAME_);
            blog.setArticlesCitations(projectName);
        } else {
            blog.setAuthor(blogDto.getAuthor());
            blog.setArticlesCitations(blogDto.getArticlesPart());
        }
        blog.setStatus(BlogStatus.ENABLE.getStatus());
        blog.setCreateTime(new Date());
        int update = blogMapper.updateByPrimaryKeySelective(blog);

        BlogTagRelationExample relationExample = new BlogTagRelationExample();
        relationExample.createCriteria().andBlogUidEqualTo(blog.getUid());
        relationMapper.deleteByExample(relationExample);
        List<Integer> tagUid = blogDto.getTagUid();
        for (Integer integer : tagUid) {
            BlogTagRelation relation = new BlogTagRelation();
            relation.setBlogUid(blog.getUid());
            relation.setTagUid(integer);
            relationMapper.insert(relation);
        }

        if (update > 0) {
            return Wrapper.success();
        }
        return Wrapper.failed();
    }

    @Transactional
    @Override
    public Wrapper delete(BlogDto blogVO) {
        Blog blog = blogMapper.selectByPrimaryKey(blogVO.getUid());
        if (blog == null) {
            return Wrapper.illegal();
        }
        blog.setStatus(BlogStatus.DISABLE.getStatus());
        int delete = blogMapper.updateByPrimaryKeySelective(blog);
        BlogTagRelationExample relationExample = new BlogTagRelationExample();
        relationExample.createCriteria().andBlogUidEqualTo(blogVO.getUid());
        relationMapper.deleteByExample(relationExample);

        if (delete > 0) {
            return Wrapper.successWithMessage(AdminMessageConstant.DELETE_SUCCESS);
        }
        return Wrapper.failed(AdminMessageConstant.DELETE_FAIL);
    }


    @Transactional
    @Override
    public Wrapper deleteBatchBlog(List<Integer> uids) {
        if (CollectionUtils.isEmpty(uids)) {
            return Wrapper.illegal();
        }
        BlogExample example = new BlogExample();
        example.createCriteria()
                .andUidIn(uids)
                .andStatusEqualTo(BlogStatus.ENABLE.getStatus());
        Blog blog = new Blog();
        blog.setStatus(BlogStatus.DISABLE.getStatus());
        int delete = blogMapper.updateByExampleSelective(blog, example);
        BlogTagRelationExample relationExample = new BlogTagRelationExample();
        relationExample.createCriteria().andBlogUidIn(uids);
        relationMapper.deleteByExample(relationExample);

        if (delete > 0) {
            return Wrapper.successWithMessage(AdminMessageConstant.DELETE_SUCCESS);
        }
        return Wrapper.failed(AdminMessageConstant.DELETE_FAIL);
    }

    /**
     * 添加时校验
     *
     * @param count
     * @param level
     * @return
     */
    private Wrapper addVerdict(Long count, Integer level) {
        //添加的时候进行判断
        switch (level) {
            case 1: {
                Long blogFirstCount = Long.valueOf(systemParamService.getSystemParamValueByKey(AdminBlogConstant.BLOG_FIRST_COUNT));
                if (count > blogFirstCount) {
                    return Wrapper.failed("一级推荐不能超过" + blogFirstCount + "个");
                }
            }
            break;

            case 2: {
                Long blogSecondCount = Long.valueOf(systemParamService.getSystemParamValueByKey(AdminBlogConstant.BLOG_SECOND_COUNT));
                if (count > blogSecondCount) {
                    return Wrapper.failed("二级推荐不能超过" + blogSecondCount + "个");
                }
            }
            break;

            case 3: {
                Long blogThirdCount = Long.valueOf(systemParamService.getSystemParamValueByKey(AdminBlogConstant.BLOG_THIRD_COUNT));
                if (count > blogThirdCount) {
                    return Wrapper.failed("三级推荐不能超过" + blogThirdCount + "个");
                }
            }
            break;

            case 4: {
                Long blogFourthCount = Long.valueOf(systemParamService.getSystemParamValueByKey(AdminBlogConstant.BLOG_FOURTH_COUNT));
                if (count > blogFourthCount) {
                    return Wrapper.failed("四级推荐不能超过" + blogFourthCount + "个");
                }
            }
            break;
            default: {
            }
        }
        return null;
    }

    @Override
    public List<BlogDto> getBlogByUids(List<Integer> uids) {
        if (!CollectionUtils.isEmpty(uids)) {
            BlogExample blogExample = new BlogExample();
            blogExample.createCriteria().andUidIn(uids).andStatusEqualTo(BlogStatus.ENABLE.getStatus());
            List<Blog> blogs = blogMapper.selectByExample(blogExample);
            List<BlogDto> resultList = MyBeanUtils.copyListProperties(blogs, BlogDto::new);


            List<Integer> coverUids = new ArrayList<>();
            List<Integer> categoryUids = new ArrayList<>();
            List<Integer> blogUids = new ArrayList<>();
            resultList.forEach(item -> {
                if (item.getCoverUid() != null) {
                    coverUids.add(item.getCoverUid());
                }
                if (item.getBlogCategoryUid() != null) {
                    categoryUids.add(item.getBlogCategoryUid());
                }
                blogUids.add(item.getUid());
            });

            Map<Integer, String> picMap = new HashMap<>();
            Map<Integer, BlogCategoryDto> blogCategoryMap = new HashMap<>();
            if (categoryUids.size() > 0) {
                BlogCategoryExample blogCategoryExample = new BlogCategoryExample();
                blogCategoryExample.createCriteria()
                        .andUidIn(categoryUids);
                List<BlogCategory> categoryList = blogCategoryMapper.selectByExample(blogCategoryExample);
                if(!CollectionUtils.isEmpty(categoryList)) {
                    List<BlogCategoryDto> blogCategoryDtos = MyBeanUtils.copyListProperties(categoryList, BlogCategoryDto::new);
                    blogCategoryDtos.forEach(item -> {
                        blogCategoryMap.put(item.getUid(), item);
                    });
                }
            }
            Wrapper<Map<Integer, String>> pictureWrapper = pictureFeignApi.getPicturesUrl(coverUids);
            if (pictureWrapper.isSuccess()) {
                picMap = pictureWrapper.getData();
            } else {
                log.error("获取图片失败, 方法：【AdminBlogGetList】");
            }
            for (BlogDto blog : resultList) {
                List<Integer> tagUids = blogTagRelationDao.getTagUidsByBlogUid(blog.getUid());
                if (!CollectionUtils.isEmpty(tagUids)) {
                    TagExample tagExample = new TagExample();
                    tagExample.createCriteria().andUidIn(tagUids);
                    List<Tag> tags = tagMapper.selectByExample(tagExample);
                    List<BlogTagDto> blogTagDtos = MyBeanUtils.copyListProperties(tags, BlogTagDto::new);
                    blog.setTagList(blogTagDtos);
                    blog.setPhotoUrl(picMap.get(blog.getCoverUid()));
                    blog.setBlogCategory(blogCategoryMap.get(blog.getBlogCategoryUid()));
                }
                blog.setBlogCategory(blogCategoryMap.get(blog.getBlogCategoryUid()));
            }
            return resultList;
        }
        return new ArrayList<>();
    }
}
